
#include <iostream>
#include "US.h"

namespace TOB{

  const char* UShost = (const char*)"localhost";
  const char* USpass =(const char*)"pass";
  std::string USnamedb="important_DB";
  const char* USusr = (const char*)"user";
  std::string UStable = "users";
  unsigned int USport = 3306;
  const std::string USfield_list[4]={"password","role","policy","name"};
  const std::string USpolicy_list[9] = {"AllowUserManagement","AllowMail","AllowFileSharing","AllowCalendar","AllowToDo","AllowDirectory","AllowTime","AllowWebServer","AllowChat"};
};

using namespace TOB;


US::US() {
  config = new Config(CONFIG);
  std::string *tmp = &config->stringValue("mysql-host");
  if(tmp->size() > 0) { UShost = tmp->c_str(); }
  tmp = &config->stringValue("mysql-user");
  if(tmp->size() > 0) { USusr = tmp->c_str(); }
  tmp = &config->stringValue("mysql-pass");
  if(tmp->size() > 0) { USpass = tmp->c_str(); }
  tmp = &config->stringValue("mysql-db");
  if(tmp->size() > 0) { USnamedb = *tmp; }
  tmp = &config->stringValue("mysql-table");
  if(tmp->size() > 0) { UStable = *tmp; }
  uint32 i = config->intValue("mysql-port");
  if(i) { USport = i; }
  connectDB();
}

US::~US() {
  delete config;
  disconnectDB();
}


/* This function get policy as int by login*/
Code::Type US::getUintByLogin(std::string login, std::string field, int& value){
                                       //If wrong data:
  int i;
  US::existenceLogin(login,i);
  if (i==1||(field!="role"&&field!="policy")) {
    Log::error("Error: not found login or wrong field or wrong value\n");
    return(Code::US_DataFetchError);
  };
                                             //Build query if connect wuth DB:
  if (mysql_ping(&mysql)<=0){
    std::string str_query=(field=="policy")?"SELECT "+field+" + 0 FROM "+USnamedb+"."+UStable+" WHERE login= '"+login+"'"+"":"SELECT "+field+" FROM "+USnamedb+"."+UStable+" WHERE login= '"+login+"'"+"";
    char* query=new char[str_query.size()+1];
    strcpy(query,str_query.c_str());
                                             //Execute query, if !=0=> we have error:
    if (mysql_query(&mysql, query )!=0){
      Log::error("Error execute require\n");
      return(Code::US_QueryError);                  
    };
                                             //Save result query and check result:
    mysql_res=mysql_use_result(&mysql);
    mysql_row=mysql_fetch_row(mysql_res);
                                             //Save result in argument 'value' and make empty memory:
    value=atoi(mysql_row[0]);
    delete[] query;
    mysql_free_result(mysql_res);
                                             //If didn't connect with database:
  } else {
    Log::error("Impossible execute require: error connect with DataBase\n");
    return (Code::US_DBDoesntRespond);                      
  };
  return(Code::Okay);
};

/*This function get field by login*/
Code::Type US::getStringByLogin(std::string login, std::string fieldName, std::string& value){
                                    //If wrong data:
  int i;
  US::existenceLogin(login,i);
  if (i==1||US::checkField(fieldName)==1) {
    Log::error("Error: not found login or wrong field or wrong value\n");
    return(Code::US_DataFetchError);
  };
                                             //Build query if connect wuth DB:
  if (mysql_ping(&mysql)<=0){
    std::string str_query="SELECT "+fieldName+" FROM "+USnamedb+"."+UStable+" WHERE login= '"+login+"'"+"";
    char* query=new char[str_query.size()+1];
    strcpy(query,str_query.c_str());
                                             //Execute query, if !=0=> we have error:
    if (mysql_query(&mysql, query )!=0){
      Log::error("Error execute require\n");
      return(Code::US_QueryError);                  
    };
                                             //Save result query and check result:
    mysql_res=mysql_use_result(&mysql);
    mysql_row=mysql_fetch_row(mysql_res);
                                             //Save result in argument 'value' and make empty memory:
    value.assign(mysql_row[0]);
    delete[] query;
    mysql_free_result(mysql_res);
                                             //If didn't connect with database:
  } else {
    Log::error("Impossible execute require: error connect with DataBase\n");
    return (Code::US_DBDoesntRespond);                      
  };
  return(Code::Okay);
}

/* This function verify login and return 1=if login non existence, 0=if login existence */
Code::Type US::existenceLogin (std::string login, int& value){

  if (mysql_ping(&mysql)<=0){        //Build query if connect with DB:
    std::string str_query="SELECT * FROM "+USnamedb+"."+UStable+" WHERE "+UStable+".login= '"+login+"'";
    char* query = new char[str_query.size()+1];
    strcpy(query, str_query.c_str());
                                           //Execute query, if !=0=> we have error:
    if (mysql_query(&mysql, query)!=0){
      Log::error("Error execute require\n");
      return(Code::US_QueryError);                  //Hear must be code error!
    };
                                         //Save result query and check result:
    mysql_res=mysql_use_result(&mysql);
    mysql_row=mysql_fetch_row(mysql_res);
                                          //Save result and return and make empty memory:
    if(mysql_row==NULL) value=1; else value=0;
    delete[] query;
    mysql_free_result(mysql_res);
                                          //If didn't connect with database:
  }else{
    Log::error("Impossible execute require: error connect with database\n");
    return(Code::US_DBDoesntRespond);                          //Hear must be code error!
  };
  return(Code::Okay);
};

/* This function update field by login using value in type :"value" or "val1,val2"(winthout spaсes!) in field Policy */
Code::Type US::updateFieldByLogin(std::string login,std::string fieldName, std::string value){
                                    //If wrong data:
  int i;
  US::existenceLogin(login,i);
  if (i==1||US::checkField(fieldName)==1||US::checkFieldValue(fieldName,value)==1) {
    Log::error("Error: not found login or wrong field or wrong value\n");
    return(Code::US_DataFetchError);
  };
                                   //Build query if connect with DB:  
  if (mysql_ping(&mysql)<=0){
    std::string str_query= (fieldName!="policy")?"UPDATE "+USnamedb+"."+UStable+" SET "+UStable+"."+fieldName+ "= '"+ value + "' WHERE login='"+ login+ "'":"UPDATE "+USnamedb+"."+UStable+" SET "+UStable+"."+fieldName+ "= "+ value + " WHERE login='"+ login+ "'"  ;
    char* query =new char[str_query.size()+1];
    strcpy(query, str_query.c_str());
                                   //Execute query, if !=0=> we have error:
    if (mysql_query(&mysql,query)!=0){
      Log::error("Error execute require\n");
      return(Code::US_QueryError);                      //Hear must be code error!
    };

    std::string even;
    even.assign(mysql_info(&mysql));
    Log::event(even);
    delete[] query;
                                   //If didn't connect with database:
  } else {
    Log::error("Impossible execute require: error connect with DataBase\n");
    return (Code::US_DBDoesntRespond);                       //Hear must be code error!
  };
  return(Code::Okay);
};

/* This function delete row by login  */
Code::Type US::deleteRowByLogin (std::string login){
                                   //If wrong data:
  int i;
  US::existenceLogin(login,i);
  if (i==1||login=="root"){
    Log::error("Error: not found login or you want delete root account\n");
    return(Code::US_DataFetchError);
  };
                                  //Build query if connect with DB:
  if (mysql_ping(&mysql)<=0){
    std::string str_query="DELETE FROM "+USnamedb+"."+UStable+" WHERE login= '"+login + "'";  
    char* query =new char[str_query.size()+1];
    strcpy(query, str_query.c_str());
                                  //Execute query, if !=0=> we have error:
    if (mysql_query(&mysql,query)!=0){
      Log::error("Error execute require\n");
      return(Code::US_QueryError);
    };
                                  //If not deleted rows, then error:
    if(mysql_affected_rows(&mysql)==0) {
      Log::error("Delete not execute\n");
      return(Code::US_QueryError);
    };

    delete[] query;
                                 //If didn't connect with database:
  } else {
    Log::error("Impossible execute require: error connect with DataBase\n");
    return (Code::US_DBDoesntRespond);
  };

  return(Code::Okay);
};

/* This function append row in DB */
Code::Type US::appendRow(std::string login, std::string password, std::string role, std::string policy, std::string name){
                                  //If wrong data:
  int i;
  US::existenceLogin(login,i);
  if (i==0||US::checkFieldValue("login",login)==1||US::checkFieldValue("password",password)==1||US::checkFieldValue("role",role)==1||US::checkFieldValue("policy",policy)==1) {
    Log::error("Error: login is already existence or wrong value\n");
    return(Code::US_DataFetchError);
  };
                                 //Build query if connect with DB: 
  if (mysql_ping(&mysql)<=0){
    std::string str_query="INSERT INTO "+USnamedb+"."+UStable+" VALUES('"+login + "','"+password+"','"+role+"',"+policy+",'"+name+"')";  
    char* query =new char[str_query.size()+1];
    strcpy(query, str_query.c_str());
                                 //Execute query, if !=0=> we have error:
    if (mysql_query(&mysql,query)!=0){
      Log::error("Error execute require\n");
      return(Code::US_QueryError);
    };

    delete[] query;
                                 //If didn't connect with database:
  } else {
    Log::error("Impossible execute require: error connect with DataBase\n");
    return (Code::US_DBDoesntRespond);                       //Hear must be code error!
  };
  return(Code::Okay);
};


/* This function check field: include or not in table  */
int US::checkField(std::string field){

  for (int i=0; i<4; i++) { if(field==USfield_list[i]) {return (0);} ;};

  return(1);
};

/* This function check value with field */
int US::checkFieldValue (std::string field, std::string value)
{
//true =0; false=1;
  if (field=="role") {
     int role_i=atoi(value.c_str());
     return ((role_i>=0&&role_i<=1)?0:1);
  };

  if (field=="policy") 
  {
    int policy_i=atoi(value.c_str());
    return ((policy_i>=0&&policy_i<=255)?0:1);
  };

  if (field=="password"||field=="login") { if (value=="") {return (1);} ;};

  return (0);

};

/* This function connect with database, using parameters in header DB.h */
int US::connectDB(){

  if (mysql_init(&mysql)==NULL){

    Log::error("Error create descriptor mysql\n"); 
    return (Code::US_DBDoesntRespond);                           //Hear must be code error!
  };

  if (mysql_real_connect(&mysql, UShost, USusr, USpass, USnamedb.c_str(), USport, NULL, 0 )==NULL){

    Log::error("Error connecting with DB\n");
    return(Code::US_DBDoesntRespond);
  };

  return(0);
};

/*This function disconnect with database*/
int US::disconnectDB(){

  mysql_close(&mysql);
  return(0);
};

